#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/pgtable.h>
#include <asm/current.h>

/**
 * @brief 内核模块初始化函数
 * 
 * 模块加载时调用此函数，获取并打印当前进程的页全局目录（PGD）地址、CR3寄存器值以及每个页目录项（PDE）的信息。
 * 
 * @return int 成功返回0
 */
static int __init print_pde_init(void) {
    struct mm_struct *mm;     ///< 当前进程的内存管理结构指针
    pgd_t *pgd;               ///< 页全局目录指针
    unsigned long cr3;        ///< CR3寄存器值，用于存储当前页目录基址
    int i;                    ///< 循环变量

    mm = current->mm; // 获取当前进程的内存管理结构
    pgd = mm->pgd;    // 获取页目录地址

    printk(KERN_INFO "Page Global Directory Address: %p\n", pgd);  ///< 打印页全局目录地址

    // 读取CR3寄存器值
    asm volatile("mov %%cr3, %0" : "=r" (cr3));
    printk(KERN_INFO "CR3 Register Value: %lx\n", cr3);            ///< 打印CR3寄存器值

    // 打印页目录的PDE信息
    for (i = 0; i < PTRS_PER_PGD; i++) {
        struct page *page;
        page = pfn_to_page(pgd_val(pgd[i]) >> PAGE_SHIFT);  ///< 转换页框号到page结构
        if (!page)
            continue;
        
        // 打印PDE信息
        printk(KERN_INFO "PDE[%d]: %lx\n", i, pgd_val(pgd[i]));    ///< 打印每个PDE的值
    }

    return 0;  ///< 返回初始化成功
}

/**
 * @brief 内核模块清理函数
 * 
 * 模块卸载时调用此函数，打印退出日志信息。
 */
static void __exit print_pde_exit(void) {
    printk(KERN_INFO "Exiting PDE Printer Module.\n"); ///< 打印模块卸载信息
}

module_init(print_pde_init); ///< 指定模块初始化函数
module_exit(print_pde_exit); ///< 指定模块退出函数

MODULE_LICENSE("GPL"); ///< 指定模块许可证为GPL
MODULE_DESCRIPTION("Print Current Process Page Directory Entries"); ///< 模块描述
MODULE_AUTHOR("Zhenxiong Chen"); ///< 模块作者
